import React, { useEffect, useRef, useState, forwardRef, useImperativeHandle } from "react";
import "./Earth2D.css";
import { LatLngPoint, LatLngPolygon, LatLngRect, LocationPoint, DetectionPoint } from "../types/earth";

interface Earth2DProps {
  dataAreas?: LatLngRect[];
  patrolAreas?: LatLngRect[]; // 新增巡视区数据
  polygons?: LatLngPolygon[];
  locationPoints?: LocationPoint[];
  tileUrlTemplate?: string; // 新增瓦片URL模版
  maxZoom?: number; // 新增maxZoom参数
  radius?: number; // 球体半径（km），用于比例尺
  onHover?: (coord: LatLngPoint | null) => void;
  onClick?: (coord: LatLngPoint | null) => void;
  onLocationHover?: (location: LocationPoint | null) => void;
  onLocationClick?: (location: LocationPoint | null) => void;
  onPatrolAreaClick?: (patrolArea: LatLngRect | null) => void; // 新增巡视区点击回调
  onPatrolAreaHover?: (patrolArea: LatLngRect | null) => void; // 新增巡视区悬停回调
  onSelectionEnd?: (
    selection: LatLngRect | null,
    intersectingRects: LatLngRect[],
    intersectingDetectionPoints: DetectionPoint[]
  ) => void;
  onSelectionChange?: (selection: LatLngRect | null) => void; // 选区变化回调
  externalSelection?: LatLngRect | null; // 外部传入的选区状态
  simulatedMetaKey?: boolean; // 模拟Meta键状态
}

export interface Earth2DRef {
  zoomIn: () => void;
  zoomOut: () => void;
  resetView: () => void;
  enterSelectionMode: () => void;
  exitSelectionMode: () => void;
  clearSelection: () => void;
}

const Earth2D = forwardRef<Earth2DRef, Earth2DProps>(
  (
    {
      dataAreas = [],
      patrolAreas = [], // 新增巡视区数据
      polygons = [],
      locationPoints = [],
      tileUrlTemplate = "/earth_tiles/{z}_{y}_{x}.jpg", // 新增瓦片URL模版，默认使用静态路径
      maxZoom = 5, // 新增maxZoom参数，默认值为5
      radius = 0,
      onHover,
      onClick,
      onLocationHover,
      onLocationClick,
      onPatrolAreaClick, // 新增巡视区点击回调
      onPatrolAreaHover, // 新增巡视区悬停回调
      onSelectionEnd,
      onSelectionChange,
      externalSelection,
      simulatedMetaKey = false,
    },
    ref
  ) => {
    const canvasRef = useRef<HTMLCanvasElement>(null);
    const [scale, setScale] = useState(1);
    const [panX, setPanX] = useState(0);
    const [panY, setPanY] = useState(0);
    const [isDragging, setIsDragging] = useState(false);
    const [isMouseDown, setIsMouseDown] = useState(false);
    const [isSelecting, setIsSelecting] = useState(false);
    const [selectionStart, setSelectionStart] = useState<{ x: number; y: number } | null>(null);
    const [selectionEnd, setSelectionEnd] = useState<{ x: number; y: number } | null>(null);
    const [lastMousePos, setLastMousePos] = useState<{ x: number; y: number } | null>(null);
    const [mouseDownPos, setMouseDownPos] = useState<{ x: number; y: number } | null>(null);
    const [currentZoomLevel, setCurrentZoomLevel] = useState(1);
    const [tileImages, setTileImages] = useState<Map<string, HTMLImageElement>>(new Map());
    const [isLoadingTiles, setIsLoadingTiles] = useState(false);
    const [displayLevel, setDisplayLevel] = useState(1); // 当前显示的层级

    // 使用useRef来获取最新的状态值
    const scaleRef = useRef(scale);
    const panXRef = useRef(panX);
    const panYRef = useRef(panY);
    const displayLevelRef = useRef(displayLevel);
    const simulatedMetaKeyRef = useRef(simulatedMetaKey);

    // 更新ref值
    useEffect(() => {
      scaleRef.current = scale;
    }, [scale]);

    useEffect(() => {
      panXRef.current = panX;
    }, [panX]);

    useEffect(() => {
      panYRef.current = panY;
    }, [panY]);

    useEffect(() => {
      displayLevelRef.current = displayLevel;
    }, [displayLevel]);

    useEffect(() => {
      simulatedMetaKeyRef.current = simulatedMetaKey;
    }, [simulatedMetaKey]);

    // 惯性拖动相关状态
    const [inertia, setInertia] = useState({ vx: 0, vy: 0 });
    const [isInertiaActive, setIsInertiaActive] = useState(false);
    const [lastMoveTime, setLastMoveTime] = useState(0);
    const [lastMoveDelta, setLastMoveDelta] = useState({ x: 0, y: 0 });

    // 圈选相关状态（与3D一致：Meta键+两次点击）
    const [is2DSelecting, setIs2DSelecting] = useState(false); // 是否处于圈选模式
    const [selectClickCount, setSelectClickCount] = useState(0); // 已点击次数
    const [selectStart, setSelectStart] = useState<{ x: number; y: number } | null>(null); // 起点
    const [selectEnd, setSelectEnd] = useState<{ x: number; y: number } | null>(null); // 终点
    // 新增：最后一次圈选的经纬度范围
    const [lastSelection, setLastSelection] = useState<LatLngRect | null>(null);
    // 新增：相交区域状态
    const [intersectedRects, setIntersectedRects] = useState<boolean[]>([]);

    const [intersectedPolygons, setIntersectedPolygons] = useState<boolean[]>([]);

    // 新增：鼠标悬停状态
    const [isHoveringLocation, setIsHoveringLocation] = useState(false);

    // 新增：图片Promise缓存，防止重复加载
    const tileImagePromiseCache = useRef(new Map());
    // 新增：tile图片加载请求唯一标识
    const tileLoadRequestId = useRef(0);

    // 获取当前级别的地图尺寸（显示尺寸始终是2048x1024）
    const getMapDimensions = (level: number) => {
      return { width: 2048, height: 1024 };
    };

    // 经纬度转屏幕坐标（墨卡托投影）
    const latLngToScreen = (lat: number, lng: number, level: number = displayLevel) => {
      // 圆柱形投影（等距圆柱投影）
      const { width, height } = getMapDimensions(level);
      const x = ((lng + 180) / 360) * width;
      const y = ((90 - lat) / 180) * height; // 纬度从90°（顶部）到-90°（底部）
      return { x, y };
    };

    // 屏幕坐标转经纬度
    const screenToLatLng = (x: number, y: number, level: number = displayLevel) => {
      const { width, height } = getMapDimensions(level);
      const lng = (x / width) * 360 - 180;
      const lat = 90 - (y / height) * 180; // 纬度从90°（顶部）到-90°（底部）
      return { lat, lng };
    };

    // 绘制地球
    const drawEarth = (ctx: CanvasRenderingContext2D) => {
      const width = ctx.canvas.width;
      const height = ctx.canvas.height;

      // 清空画布
      ctx.clearRect(0, 0, width, height);

      // 应用变换
      ctx.save();
      ctx.translate(panX, panY);
      ctx.scale(scale, scale);

      // 绘制地球瓦片图（支持无限循环）
      const drawTileAtPosition = (img: HTMLImageElement, x: number, y: number, width: number, height: number) => {
        ctx.drawImage(img, x, y, width, height);
      };

      if (displayLevel === 1) {
        // 1级显示1_0_0.jpg，支持无限循环
        const img = tileImages.get("1_0_0");

        if (img) {
          // 计算需要绘制多少个地图副本来覆盖整个可视区域
          const canvasWidth = width / scale;
          const canvasHeight = height / scale;
          const { width: mapWidth, height: mapHeight } = getMapDimensions(1);

          // 计算起始位置
          const startX = Math.floor(-panX / scale / mapWidth) * mapWidth;
          const endX = Math.ceil((-panX + canvasWidth) / scale / mapWidth) * mapWidth;

          for (let x = startX; x <= endX; x += mapWidth) {
            drawTileAtPosition(img, x, 0, mapWidth, mapHeight);
          }
        } else {
          // 如果没有加载到图片，显示默认背景
          ctx.fillStyle = "#e6f3ff";
          ctx.fillRect(0, 0, 2048, 1024);
        }
      } else if (displayLevel >= 2) {
        // 其他级别显示瓦片，但level1底图要一直显示
        const level = displayLevel;
        const rows = Math.pow(2, level - 1);
        const cols = Math.pow(2, level);

        // 先绘制level1底图作为背景
        const level1Img = tileImages.get("1_0_0");
        if (level1Img) {
          const canvasWidth = width / scale;
          const canvasHeight = height / scale;
          const { width: mapWidth, height: mapHeight } = getMapDimensions(1);
          const startX = Math.floor(-panX / scale / mapWidth) * mapWidth;
          const endX = Math.ceil((-panX + canvasWidth) / scale / mapWidth) * mapWidth;
          for (let x = startX; x <= endX; x += mapWidth) {
            drawTileAtPosition(level1Img, x, 0, mapWidth, mapHeight);
          }
        }

        // 绘制当前级别的瓦片（支持无限循环）
        const canvasWidth = width / scale;
        const canvasHeight = height / scale;
        const displayMapWidth = 2048; // 显示地图宽度
        const displayMapHeight = 1024; // 显示地图高度
        const totalMapWidth = cols * 1024; // 瓦片总宽度
        const totalMapHeight = rows * 1024; // 瓦片总高度

        // 计算需要绘制的瓦片副本
        const startX = Math.floor(-panX / scale / displayMapWidth) * displayMapWidth;
        const endX = Math.ceil((-panX + canvasWidth) / scale / displayMapWidth) * displayMapWidth;

        // 绘制当前级别的瓦片（支持无限循环）
        for (let mapOffsetX = startX; mapOffsetX <= endX; mapOffsetX += displayMapWidth) {
          for (let y = 0; y < rows; y++) {
            for (let x = 0; x < cols; x++) {
              const key = `${level}_${x}_${y}`;
              const img = tileImages.get(key);
              if (img) {
                // 将瓦片缩放到显示尺寸
                const tileX = mapOffsetX + x * 1024 * (displayMapWidth / totalMapWidth);
                const tileY = y * 1024 * (displayMapHeight / totalMapHeight);
                const tileWidth = 1024 * (displayMapWidth / totalMapWidth);
                const tileHeight = 1024 * (displayMapHeight / totalMapHeight);
                ctx.drawImage(img, tileX, tileY, tileWidth, tileHeight);
              }
            }
          }
        }
      } else {
        // 如果没有加载到图片，显示默认背景
        ctx.fillStyle = "#e6f3ff";
        ctx.fillRect(0, 0, 2048, 1024);
      }

      // 绘制dataAreas（支持无限循环）
      const drawRect = (rect: LatLngRect, index: number, offsetX: number = 0) => {
        const topLeft = latLngToScreen(rect.maxLat, rect.minLng);
        const bottomRight = latLngToScreen(rect.minLat, rect.maxLng);

        // 根据相交状态决定颜色
        const isIntersected = intersectedRects[index] || false;

        ctx.strokeStyle = isIntersected ? "#ff0000" : "#00ff00";
        // 固定线宽，不随缩放变化
        ctx.lineWidth = 1 / scale;

        ctx.beginPath();
        ctx.rect(topLeft.x + offsetX, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y);
        ctx.stroke();
      };

      // 绘制巡视区（使用不同颜色）
      const drawPatrolArea = (area: LatLngRect, index: number, offsetX: number = 0) => {
        const topLeft = latLngToScreen(area.maxLat, area.minLng);
        const bottomRight = latLngToScreen(area.minLat, area.maxLng);

        // 巡视区使用橙色
        ctx.strokeStyle = "#ff6b35";
        // 固定线宽，不随缩放变化
        ctx.lineWidth = 2 / scale;

        ctx.beginPath();
        ctx.rect(topLeft.x + offsetX, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y);
        ctx.stroke();
      };

      // 绘制polygons（支持无限循环）
      const drawPolygon = (polygon: LatLngPolygon, index: number, offsetX: number = 0) => {
        if (polygon.points.length > 0) {
          ctx.fillStyle = `rgba(100, 255, 100, 0.3)`;
          // 根据相交状态决定颜色
          const isIntersected = intersectedPolygons[index] || false;
          ctx.strokeStyle = isIntersected ? "#ff0000" : "#00ff00";
          // 固定线宽，不随缩放变化
          ctx.lineWidth = 1 / scale;

          ctx.beginPath();
          const firstPoint = latLngToScreen(polygon.points[0].lat, polygon.points[0].lng);
          ctx.moveTo(firstPoint.x + offsetX, firstPoint.y);

          for (let i = 1; i < polygon.points.length; i++) {
            const point = latLngToScreen(polygon.points[i].lat, polygon.points[i].lng);
            ctx.lineTo(point.x + offsetX, point.y);
          }

          ctx.closePath();
          ctx.fill();
          ctx.stroke();
        }
      };

      // 计算需要绘制的区域副本
      const canvasWidth = width / scale;
      const { width: mapWidth } = getMapDimensions(displayLevel);
      const startX = Math.floor(-panX / scale / mapWidth) * mapWidth;
      const endX = Math.ceil((-panX + canvasWidth) / scale / mapWidth) * mapWidth;

      // 绘制地点标记
      const drawLocationPoint = (location: LocationPoint, offsetX: number = 0) => {
        const center = latLngToScreen(location.center_latitude, location.center_longitude);
        const radius = 6; // 固定大小，不随缩放变化

        // 绘制外圈
        ctx.beginPath();
        ctx.arc(center.x + offsetX, center.y, radius + 2, 0, 2 * Math.PI);
        ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
        ctx.fill();

        // 绘制内圈
        ctx.beginPath();
        ctx.arc(center.x + offsetX, center.y, radius, 0, 2 * Math.PI);
        ctx.fillStyle = "#1890ff";
        ctx.fill();

        // 绘制中心点
        ctx.beginPath();
        ctx.arc(center.x + offsetX, center.y, radius / 2, 0, 2 * Math.PI);
        ctx.fillStyle = "#ffffff";
        ctx.fill();

        // 绘制标签
        const label = location.name;
        const textX = center.x + offsetX + radius + 5;
        const textY = center.y - 8;

        // 根据缩放比例调整字体大小
        const fontSize = Math.max(14, Math.min(20, 14 / scale));
        ctx.font = `bold ${fontSize}px Arial`;
        ctx.textAlign = "left";
        ctx.textBaseline = "middle";

        // 绘制文字阴影（多层阴影实现更稳定的效果）
        ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
        ctx.fillText(label, textX + 1, textY + 1);
        ctx.fillText(label, textX + 1, textY);
        ctx.fillText(label, textX, textY + 1);

        // 绘制文字
        ctx.fillStyle = "#ffffff";
        ctx.fillText(label, textX, textY);
      };

      // 绘制所有副本的区域
      for (let x = startX; x <= endX; x += mapWidth) {
        dataAreas.forEach((rect, index) => {
          drawRect(rect, index, x);
        });

        // 绘制巡视区（使用不同颜色）
        patrolAreas.forEach((area, index) => {
          drawPatrolArea(area, index, x);
        });

        polygons.forEach((polygon, index) => {
          drawPolygon(polygon, index, x);
        });

        // 探测点在地图变换后绘制，不在这里绘制
      }

      ctx.restore();

      // 在地图变换之后绘制区域标签（使用屏幕坐标，固定文字大小）
      for (let x = startX; x <= endX; x += mapWidth) {
        dataAreas.forEach((rect, index) => {
          const label = rect.name || `区域${index + 1}`;
          const topLeft = latLngToScreen(rect.maxLat, rect.minLng);
          const bottomRight = latLngToScreen(rect.minLat, rect.maxLng);

          // 计算区域中心位置
          const centerX = (topLeft.x + bottomRight.x) / 2;
          const centerY = (topLeft.y + bottomRight.y) / 2;

          const textX = (centerX + x) * scale + panX;
          const textY = centerY * scale + panY;

          // 文字大小固定，不随地图缩放变化
          ctx.font = "bold 14px Arial";
          ctx.textAlign = "center";
          ctx.textBaseline = "middle";

          // 绘制多层文字实现阴影效果（更稳定）
          // 1. 绘制黑色阴影（多个偏移位置）
          ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
          ctx.fillText(label, textX + 1, textY + 1);
          ctx.fillText(label, textX + 1, textY);
          ctx.fillText(label, textX, textY + 1);

          // 2. 绘制白色文字
          ctx.fillStyle = "#ffffff";
          ctx.fillText(label, textX, textY);
        });
      }

      // 在地图变换之后绘制巡视区标签（使用屏幕坐标，固定文字大小）
      for (let x = startX; x <= endX; x += mapWidth) {
        patrolAreas.forEach((area, index) => {
          const label = area.name || `巡视区${index + 1}`;
          const topLeft = latLngToScreen(area.maxLat, area.minLng);
          const bottomRight = latLngToScreen(area.minLat, area.maxLng);

          // 计算区域中心位置
          const centerX = (topLeft.x + bottomRight.x) / 2;
          const centerY = (topLeft.y + bottomRight.y) / 2;

          const textX = (centerX + x) * scale + panX;
          const textY = centerY * scale + panY;

          // 文字大小固定，不随地图缩放变化
          ctx.font = "bold 14px Arial";
          ctx.textAlign = "center";
          ctx.textBaseline = "middle";

          // 绘制多层文字实现阴影效果（更稳定）
          // 1. 绘制黑色阴影（多个偏移位置）
          ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
          ctx.fillText(label, textX + 1, textY + 1);
          ctx.fillText(label, textX + 1, textY);
          ctx.fillText(label, textX, textY + 1);

          // 2. 绘制橙色文字（与巡视区边框颜色一致）
          ctx.fillStyle = "#ff6b35";
          ctx.fillText(label, textX, textY);
        });
      }

      // 在地图变换之后绘制地点标记（使用屏幕坐标，固定大小）
      // 获取当前地图级别
      const currentLevel = getZoomLevel();

      // 根据地图级别过滤location，只显示level小于等于地图level的location
      const filteredLocations = locationPoints.filter((location) => {
        return location.level <= currentLevel;
      });

      for (let x = startX; x <= endX; x += mapWidth) {
        filteredLocations.forEach((location) => {
          const center = latLngToScreen(location.center_latitude, location.center_longitude);
          const screenX = (center.x + x) * scale + panX;
          const screenY = center.y * scale + panY;
          const radius = 6; // 固定大小，不随缩放变化

          // 绘制外圈
          ctx.beginPath();
          ctx.arc(screenX, screenY, radius + 2, 0, 2 * Math.PI);
          ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
          ctx.fill();

          // 绘制内圈
          ctx.beginPath();
          ctx.arc(screenX, screenY, radius, 0, 2 * Math.PI);
          ctx.fillStyle = "#1890ff";
          ctx.fill();

          // 绘制中心点
          ctx.beginPath();
          ctx.arc(screenX, screenY, radius / 2, 0, 2 * Math.PI);
          ctx.fillStyle = "#ffffff";
          ctx.fill();

          // 绘制标签
          const label = location.name;
          const textX = screenX + radius + 5;
          const textY = screenY - 8;

          // 标签文字大小固定，不随缩放变化
          ctx.font = "bold 14px Arial";
          ctx.textAlign = "left";
          ctx.textBaseline = "middle";

          // 绘制文字阴影（多层阴影实现更稳定的效果）
          ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
          ctx.fillText(label, textX + 1, textY + 1);
          ctx.fillText(label, textX + 1, textY);
          ctx.fillText(label, textX, textY + 1);

          // 绘制文字
          ctx.fillStyle = "#ffffff";
          ctx.fillText(label, textX, textY);
        });
      }

      // 绘制选择框（在变换之后，使用屏幕坐标）
      if (selectionStart && selectionEnd) {
        ctx.strokeStyle = "#0066ff";
        // 固定线宽，不随缩放变化
        ctx.lineWidth = 1;
        ctx.setLineDash([5, 5]);

        ctx.beginPath();
        ctx.rect(
          Math.min(selectionStart.x, selectionEnd.x),
          Math.min(selectionStart.y, selectionEnd.y),
          Math.abs(selectionEnd.x - selectionStart.x),
          Math.abs(selectionEnd.y - selectionStart.y)
        );
        ctx.stroke();

        ctx.setLineDash([]);
      }
    };

    // 绘制比例尺
    const drawScale = (ctx: CanvasRenderingContext2D) => {
      const width = ctx.canvas.width;
      const height = ctx.canvas.height;

      // 使用 pxToKm2DMap 公式：kmPerPx = (2πR / mapWidthPx) * cos(latitude)
      const mapWidthPx = 2048; // 赤道满幅像素宽
      const circumferenceKm = 2 * Math.PI * radius;
      const kmPerPixelEquator = circumferenceKm / mapWidthPx;
      // 使用赤道基准，移除纬度因子，保证随缩放单调
      const kmPerPixel = kmPerPixelEquator / Math.max(scale, 1e-6);
      const scaleLengthPx = 100;
      const scaleLengthKm = kmPerPixel * scaleLengthPx;

      ctx.save();

      // 绘制背景
      ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
      ctx.fillRect(10, height - 50, scaleLengthPx + 20, 40);

      // 绘制文字（在上方）
      const text = `${scaleLengthKm.toFixed(0)} km`;
      ctx.fillStyle = "#ffffff";
      // 比例尺文字大小固定，不受缩放影响
      ctx.font = "bold 14px Arial";
      ctx.textAlign = "left";
      ctx.textBaseline = "bottom";
      ctx.fillText(text, 20, height - 30);

      // 绘制比例尺线条（在下方）
      const lineY = height - 25;
      const lineStartX = 20;
      const lineEndX = 20 + scaleLengthPx;

      // 绘制主线条
      ctx.strokeStyle = "#ffffff";
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.moveTo(lineStartX, lineY);
      ctx.lineTo(lineEndX, lineY);
      ctx.stroke();

      // 绘制两端竖线（形成括号效果）
      const bracketHeight = 6;

      // 左端竖线
      ctx.beginPath();
      ctx.moveTo(lineStartX, lineY - bracketHeight);
      ctx.lineTo(lineStartX, lineY + bracketHeight);
      ctx.stroke();

      // 右端竖线
      ctx.beginPath();
      ctx.moveTo(lineEndX, lineY - bracketHeight);
      ctx.lineTo(lineEndX, lineY + bracketHeight);
      ctx.stroke();

      ctx.restore();
    };

    // 绘制坐标信息
    const drawCoordInfo = (ctx: CanvasRenderingContext2D, mouseX: number, mouseY: number) => {
      if (mouseX >= 0 && mouseY >= 0) {
        const screenX = (mouseX - panX) / scale;
        const screenY = (mouseY - panY) / scale;
        const coord = screenToLatLng(screenX, screenY);

        ctx.save();
        ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
        ctx.fillRect(mouseX + 10, mouseY - 30, 150, 25);

        ctx.fillStyle = "#ffffff";
        // 坐标信息文字大小固定，不受缩放影响
        ctx.font = "bold 13px Arial";
        ctx.fillText(`纬度: ${coord.lat.toFixed(2)}° 经度: ${coord.lng.toFixed(2)}°`, mouseX + 15, mouseY - 15);

        ctx.restore();
      }
    };

    // 渲染函数（增加圈选框渲染和选区高亮）
    const render = () => {
      const canvas = canvasRef.current;
      if (!canvas) {
        return;
      }
      const ctx = canvas.getContext("2d");
      if (!ctx) {
        return;
      }
      drawEarth(ctx);
      drawScale(ctx);
      // 绘制已完成的选区高亮（保持显示，随地图平移缩放，并支持左右无限循环，支持经度归一化）
      // 优先使用外部传入的选区状态，如果没有则使用内部状态
      const selectionToRender = externalSelection || lastSelection;
      if (selectionToRender) {
        ctx.save();
        ctx.strokeStyle = "#ffcc00";
        ctx.lineWidth = 2;
        const { width: mapWidth } = getMapDimensions(displayLevel);
        // 保持原始经度范围，不强制归一化
        let minLat = selectionToRender.minLat;
        let maxLat = selectionToRender.maxLat;
        let minLng = selectionToRender.minLng;
        let maxLng = selectionToRender.maxLng;
        // 处理跨越180°经线的情况
        const rect = { minLat, maxLat, minLng, maxLng };
        // 无限循环渲染
        const canvasWidth = canvas.width;
        // 处理跨越经线的情况
        const lngSpan = getLngSpan(minLng, maxLng);

        if (lngSpan <= 180) {
          // 正常情况：没有跨越经线
          const topLeft = latLngToScreen(rect.maxLat, rect.minLng);
          const bottomRight = latLngToScreen(rect.minLat, rect.maxLng);
          const x1 = topLeft.x * scale + panX;
          const y1 = topLeft.y * scale + panY;
          const x2 = bottomRight.x * scale + panX;
          const y2 = bottomRight.y * scale + panY;
          const startOffset = Math.floor((0 - x1) / (mapWidth * scale)) * mapWidth * scale;
          const endOffset = Math.ceil((canvasWidth - x1) / (mapWidth * scale)) * mapWidth * scale;
          for (let offset = startOffset; offset <= endOffset; offset += mapWidth * scale) {
            ctx.beginPath();
            ctx.rect(x1 + offset, y1, x2 - x1, y2 - y1);
            ctx.stroke();
          }
        } else {
          // 跨越经线的情况，需要绘制两个矩形
          // 确定跨越的是0度还是180度经线
          const isCrossingZero = (minLng < 0 && maxLng > 0) || (minLng > 0 && maxLng < 0);

          if (isCrossingZero) {
            // 跨越0度经线
            // 第一个矩形：从minLng到0度
            const topLeft1 = latLngToScreen(rect.maxLat, rect.minLng);
            const bottomRight1 = latLngToScreen(rect.minLat, 0);
            const x1_1 = topLeft1.x * scale + panX;
            const y1_1 = topLeft1.y * scale + panY;
            const x2_1 = bottomRight1.x * scale + panX;
            const y2_1 = bottomRight1.y * scale + panY;
            const startOffset1 = Math.floor((0 - x1_1) / (mapWidth * scale)) * mapWidth * scale;
            const endOffset1 = Math.ceil((canvasWidth - x1_1) / (mapWidth * scale)) * mapWidth * scale;
            for (let offset = startOffset1; offset <= endOffset1; offset += mapWidth * scale) {
              ctx.beginPath();
              ctx.rect(x1_1 + offset, y1_1, x2_1 - x1_1, y2_1 - y1_1);
              ctx.stroke();
            }

            // 第二个矩形：从0度到maxLng
            const topLeft2 = latLngToScreen(rect.maxLat, 0);
            const bottomRight2 = latLngToScreen(rect.minLat, rect.maxLng);
            const x1_2 = topLeft2.x * scale + panX;
            const y1_2 = topLeft2.y * scale + panY;
            const x2_2 = bottomRight2.x * scale + panX;
            const y2_2 = bottomRight2.y * scale + panY;
            const startOffset2 = Math.floor((0 - x1_2) / (mapWidth * scale)) * mapWidth * scale;
            const endOffset2 = Math.ceil((canvasWidth - x1_2) / (mapWidth * scale)) * mapWidth * scale;
            for (let offset = startOffset2; offset <= endOffset2; offset += mapWidth * scale) {
              ctx.beginPath();
              ctx.rect(x1_2 + offset, y1_2, x2_2 - x1_2, y2_2 - y1_2);
              ctx.stroke();
            }
          } else {
            // 跨越180度经线
            // 第一个矩形：从minLng到180度
            const topLeft1 = latLngToScreen(rect.maxLat, rect.minLng);
            const bottomRight1 = latLngToScreen(rect.minLat, 180);
            const x1_1 = topLeft1.x * scale + panX;
            const y1_1 = topLeft1.y * scale + panY;
            const x2_1 = bottomRight1.x * scale + panX;
            const y2_1 = bottomRight1.y * scale + panY;
            const startOffset1 = Math.floor((0 - x1_1) / (mapWidth * scale)) * mapWidth * scale;
            const endOffset1 = Math.ceil((canvasWidth - x1_1) / (mapWidth * scale)) * mapWidth * scale;
            for (let offset = startOffset1; offset <= endOffset1; offset += mapWidth * scale) {
              ctx.beginPath();
              ctx.rect(x1_1 + offset, y1_1, x2_1 - x1_1, y2_1 - y1_1);
              ctx.stroke();
            }

            // 第二个矩形：从-180度到maxLng
            const topLeft2 = latLngToScreen(rect.maxLat, -180);
            const bottomRight2 = latLngToScreen(rect.minLat, rect.maxLng);
            const x1_2 = topLeft2.x * scale + panX;
            const y1_2 = topLeft2.y * scale + panY;
            const x2_2 = bottomRight2.x * scale + panX;
            const y2_2 = bottomRight2.y * scale + panY;
            const startOffset2 = Math.floor((0 - x1_2) / (mapWidth * scale)) * mapWidth * scale;
            const endOffset2 = Math.ceil((canvasWidth - x1_2) / (mapWidth * scale)) * mapWidth * scale;
            for (let offset = startOffset2; offset <= endOffset2; offset += mapWidth * scale) {
              ctx.beginPath();
              ctx.rect(x1_2 + offset, y1_2, x2_2 - x1_2, y2_2 - y1_2);
              ctx.stroke();
            }
          }
        }
        ctx.restore();
      }
      // 绘制圈选框（Meta键+两次点击模式，实时预览）
      if (is2DSelecting && selectStart && selectEnd) {
        ctx.save();
        ctx.strokeStyle = "#ffcc00";
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.rect(
          Math.min(selectStart.x, selectEnd.x),
          Math.min(selectStart.y, selectEnd.y),
          Math.abs(selectEnd.x - selectStart.x),
          Math.abs(selectEnd.y - selectStart.y)
        );
        ctx.stroke();
        ctx.restore();
      }
    };

    // 计算经度最小弧长（考虑跨±180°）
    const getLngSpan = (lng1: number, lng2: number) => {
      const d = Math.abs(lng1 - lng2);
      return d > 180 ? 360 - d : d;
    };

    // 计算两个矩形是否相交
    const rectIntersects = (rect1: LatLngRect, rect2: LatLngRect) => {
      // 纬度检查
      if (rect1.maxLat < rect2.minLat || rect1.minLat > rect2.maxLat) {
        return false;
      }

      // 先归一化选区的经度到-180到180范围
      const normalizeLng = (lng: number) => {
        // 先处理大数值，避免浮点数精度问题
        const cycles = Math.floor(lng / 360);
        lng = lng - cycles * 360;

        // 然后归一化到-180到180范围
        while (lng > 180) lng -= 360;
        while (lng < -180) lng += 360;
        return lng;
      };

      const normMinLng = normalizeLng(rect2.minLng);
      const normMaxLng = normalizeLng(rect2.maxLng);

      // 检查是否跨越经线
      // 方法1：归一化后minLng > maxLng
      // 方法2：原始经度跨度超过180度
      const originalSpan = Math.abs(rect2.maxLng - rect2.minLng);
      const isCrossingMeridian = normMinLng > normMaxLng || originalSpan > 180;

      if (!isCrossingMeridian) {
        // 正常情况：没有跨越经线，使用简单的AABB检查
        const result = !(rect1.maxLng < normMinLng || rect1.minLng > normMaxLng);

        return result;
      } else {
        // 跨越经线的情况：检查区域是否与选区的任一部分相交
        // 选区跨越了经线，所以区域要么与minLng到180度部分相交，要么与-180度到maxLng部分相交
        const intersectsFirstPart = !(rect1.maxLng < normMinLng || rect1.minLng > 180);
        const intersectsSecondPart = !(rect1.maxLng < -180 || rect1.minLng > normMaxLng);

        return intersectsFirstPart || intersectsSecondPart;
      }
    };

    // 计算多边形与矩形是否相交（简化版本）
    const polygonIntersectsRect = (polygon: LatLngPolygon, rect: LatLngRect) => {
      // 处理跨越180度经线的情况
      const lngSpan = getLngSpan(rect.minLng, rect.maxLng);

      // 检查多边形的任何点是否在矩形内
      for (const point of polygon.points) {
        // 纬度检查
        if (point.lat >= rect.minLat && point.lat <= rect.maxLat) {
          if (lngSpan <= 180) {
            // 正常情况：没有跨越经线
            if (point.lng >= rect.minLng && point.lng <= rect.maxLng) {
              return true;
            }
          } else {
            // 跨越经线的情况：点可能在选区的任一部分
            if (point.lng >= rect.minLng || point.lng <= (rect.maxLng > 180 ? rect.maxLng - 360 : rect.maxLng)) {
              return true;
            }
          }
        }
      }
      return false;
    };

    // 判断点是否在矩形内（处理跨越经线情况）
    const pointIntersectsRect = (point: { lat: number; lng: number }, rect: LatLngRect) => {
      // 纬度检查
      if (point.lat < rect.minLat || point.lat > rect.maxLat) {
        return false;
      }

      // 先归一化选区的经度到-180到180范围
      const normalizeLng = (lng: number) => {
        // 先处理大数值，避免浮点数精度问题
        const cycles = Math.floor(lng / 360);
        lng = lng - cycles * 360;

        // 然后归一化到-180到180范围
        while (lng > 180) lng -= 360;
        while (lng < -180) lng += 360;
        return lng;
      };

      const normMinLng = normalizeLng(rect.minLng);
      const normMaxLng = normalizeLng(rect.maxLng);

      // 检查是否跨越经线
      const originalSpan = Math.abs(rect.maxLng - rect.minLng);
      const isCrossingMeridian = normMinLng > normMaxLng || originalSpan > 180;

      if (!isCrossingMeridian) {
        // 正常情况：没有跨越经线，使用简单的AABB检查
        return point.lng >= normMinLng && point.lng <= normMaxLng;
      } else {
        // 跨越经线的情况：点可能在选区的任一部分
        const intersectsFirstPart = point.lng >= normMinLng && point.lng <= 180;
        const intersectsSecondPart = point.lng >= -180 && point.lng <= normMaxLng;

        return intersectsFirstPart || intersectsSecondPart;
      }
    };

    // 更新相交状态
    const updateIntersectedState = (selection: LatLngRect) => {
      const newIntersectedRects = dataAreas.map((rect) => rectIntersects(rect, selection));
      const newIntersectedPolygons = polygons.map((polygon) => polygonIntersectsRect(polygon, selection));

      setIntersectedRects(newIntersectedRects);
      setIntersectedPolygons(newIntersectedPolygons);
    };

    // 处理鼠标事件（重写，支持3D一致圈选）
    const handleMouseDown = (e: React.MouseEvent) => {
      const rect = canvasRef.current?.getBoundingClientRect();
      if (!rect) {
        return;
      }
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;

      // 停止惯性拖动
      setIsInertiaActive(false);
      setInertia({ vx: 0, vy: 0 });

      // 仅在未按Meta键时记录鼠标按下状态
      if (e.button === 0 && !e.metaKey && !simulatedMetaKeyRef.current) {
        setIsMouseDown(true);
        setMouseDownPos({ x, y });
        setLastMousePos({ x, y });
      }
    };

    // 鼠标点击（用于圈选，Meta键+两次点击）
    const handleMouseClick = (e: React.MouseEvent) => {
      const rect = canvasRef.current?.getBoundingClientRect();
      if (!rect) {
        return;
      }
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;

      // 如果发生了拖拽，不处理点击事件
      if (isDragging) {
        return;
      }

      // 在Meta键按下或模拟Meta键时处理圈选
      if (e.metaKey || simulatedMetaKeyRef.current) {
        if (selectClickCount === 0) {
          setIs2DSelecting(true);
          setSelectStart({ x, y });
          setSelectEnd({ x, y });
          setSelectClickCount(1);
          // 清除之前的选区坐标显示
          onSelectionChange?.(null);
        } else if (selectClickCount === 1 && is2DSelecting && selectStart) {
          setSelectEnd({ x, y });
          // 计算经纬度范围
          const startScreenX = (selectStart.x - panX) / scale;
          const startScreenY = (selectStart.y - panY) / scale;
          const endScreenX = (x - panX) / scale;
          const endScreenY = (y - panY) / scale;
          const startCoord = screenToLatLng(startScreenX, startScreenY);
          const endCoord = screenToLatLng(endScreenX, endScreenY);
          // 判断经度跨度
          const lngSpan = getLngSpan(startCoord.lng, endCoord.lng);
          if (lngSpan > 180) {
            // 超过180°，不允许圈选，清除状态
            setIs2DSelecting(false);
            setSelectClickCount(0);
            setSelectStart(null);
            setSelectEnd(null);
            // 清除选区坐标显示
            onSelectionChange?.(null);
            return;
          }
          // 限制经度跨度不超过360度
          let finalStartLng = startCoord.lng;
          let finalEndLng = endCoord.lng;
          const rawSpan = Math.abs(endCoord.lng - startCoord.lng);
          if (rawSpan > 360) {
            // 超过360度，限制为360度
            if (endCoord.lng > startCoord.lng) {
              finalEndLng = startCoord.lng + 360;
            } else {
              finalEndLng = startCoord.lng - 360;
            }
          }
          // 合法圈选，确保minLng <= maxLng
          const selection: LatLngRect = {
            minLat: Math.min(startCoord.lat, endCoord.lat),
            maxLat: Math.max(startCoord.lat, endCoord.lat),
            minLng: Math.min(finalStartLng, finalEndLng),
            maxLng: Math.max(finalStartLng, finalEndLng),
          };

          // 查找与选区相交的dataAreas
          const intersectingRects = dataAreas.filter((rect) => rectIntersects(rect, selection));

          onSelectionEnd?.(selection, intersectingRects, []);
          setLastSelection(selection); // 记录最后一次圈选
          updateIntersectedState(selection); // 更新相交状态
          // 保留选区坐标显示，不清除
          onSelectionChange?.(selection);
          setIs2DSelecting(false);
          setSelectClickCount(0);
          setSelectStart(null);
          setSelectEnd(null);
        }
      } else {
        // 非圈选模式下，普通点击
        if (!isSelecting) {
          // 先检测巡视区点击
          const clickedPatrolArea = getPatrolAreaAtPoint(x, y);
          if (clickedPatrolArea) {
            onPatrolAreaClick?.(clickedPatrolArea);
            return; // 如果点击了巡视区，不触发其他点击
          }

          // 再检测地点标记点击
          const clickedLocation = getLocationAtPoint(x, y);
          if (clickedLocation) {
            onLocationClick?.(clickedLocation);
            return; // 如果点击了地点标记，不触发地图坐标点击
          }

          // 如果没有点击任何标记，则触发地图坐标点击
          const screenX = (x - panX) / scale;
          const screenY = (y - panY) / scale;
          const coord = screenToLatLng(screenX, screenY);
          onClick?.(coord);
        }
      }
    };

    // 检测鼠标是否在地点标记上
    const getLocationAtPoint = (screenX: number, screenY: number): LocationPoint | null => {
      const { width: mapWidth } = getMapDimensions(displayLevel);

      // 获取当前地图级别
      const currentLevel = getZoomLevel();

      // 根据地图级别过滤location，只检测level小于等于地图level的location
      const filteredLocations = locationPoints.filter((location) => {
        return location.level <= currentLevel;
      });

      for (const location of filteredLocations) {
        const locationScreen = latLngToScreen(location.center_latitude, location.center_longitude);

        // 计算需要检查的地图副本范围
        const canvasWidth = canvasRef.current?.width || 0;
        const startOffset = Math.floor((0 - (locationScreen.x * scale + panX)) / (mapWidth * scale)) * mapWidth * scale;
        const endOffset =
          Math.ceil((canvasWidth - (locationScreen.x * scale + panX)) / (mapWidth * scale)) * mapWidth * scale;

        // 检查所有副本中的地点标记
        for (let offset = startOffset; offset <= endOffset; offset += mapWidth * scale) {
          const locationScreenX = locationScreen.x * scale + panX + offset;
          const locationScreenY = locationScreen.y * scale + panY;

          const distance = Math.sqrt(Math.pow(screenX - locationScreenX, 2) + Math.pow(screenY - locationScreenY, 2));

          // 检测范围固定，不随缩放变化
          const detectionRadius = 15;
          if (distance <= detectionRadius) {
            return location;
          }
        }
      }

      return null;
    };

    // 检测鼠标是否在巡视区上
    const getPatrolAreaAtPoint = (screenX: number, screenY: number): LatLngRect | null => {
      const { width: mapWidth } = getMapDimensions(displayLevel);

      for (const area of patrolAreas) {
        const topLeft = latLngToScreen(area.maxLat, area.minLng);
        const bottomRight = latLngToScreen(area.minLat, area.maxLng);

        // 计算需要检查的地图副本范围
        const canvasWidth = canvasRef.current?.width || 0;
        const startOffset = Math.floor((0 - (topLeft.x * scale + panX)) / (mapWidth * scale)) * mapWidth * scale;
        const endOffset = Math.ceil((canvasWidth - (topLeft.x * scale + panX)) / (mapWidth * scale)) * mapWidth * scale;

        // 检查所有副本中的巡视区
        for (let offset = startOffset; offset <= endOffset; offset += mapWidth * scale) {
          const areaScreenX = topLeft.x * scale + panX + offset;
          const areaScreenY = topLeft.y * scale + panY;
          const areaWidth = (bottomRight.x - topLeft.x) * scale;
          const areaHeight = (bottomRight.y - topLeft.y) * scale;

          // 检测点击是否在巡视区矩形内
          if (
            screenX >= areaScreenX &&
            screenX <= areaScreenX + areaWidth &&
            screenY >= areaScreenY &&
            screenY <= areaScreenY + areaHeight
          ) {
            return area;
          }
        }
      }

      return null;
    };

    const handleMouseMove = (e: React.MouseEvent) => {
      const rect = canvasRef.current?.getBoundingClientRect();
      if (!rect) {
        return;
      }
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;
      const currentTime = Date.now();

      // 检查是否应该开始拖拽（鼠标按下且移动距离超过阈值）
      if (isMouseDown && mouseDownPos && !isDragging) {
        const moveDistance = Math.sqrt(Math.pow(x - mouseDownPos.x, 2) + Math.pow(y - mouseDownPos.y, 2));
        if (moveDistance > 5) {
          // 移动距离超过5像素才开始拖拽
          setIsDragging(true);
        }
      }

      // 更新坐标信息
      const screenX = (x - panX) / scale;
      const screenY = (y - panY) / scale;
      const coord = screenToLatLng(screenX, screenY);
      onHover?.(coord);

      // 检测地点标记悬停
      const hoveredLocation = getLocationAtPoint(x, y);
      onLocationHover?.(hoveredLocation);

      // 更新悬停状态
      setIsHoveringLocation(!!hoveredLocation);

      // 检测巡视区悬停
      const hoveredPatrolArea = getPatrolAreaAtPoint(x, y);
      onPatrolAreaHover?.(hoveredPatrolArea);

      // 圈选模式下，实时更新终点
      if (is2DSelecting && selectClickCount === 1 && selectStart) {
        // 判断经度跨度，超180°不显示预览
        const startScreenX = (selectStart.x - panX) / scale;
        const startScreenY = (selectStart.y - panY) / scale;
        const startCoord = screenToLatLng(startScreenX, startScreenY);
        const lngSpan = getLngSpan(startCoord.lng, coord.lng);
        if (lngSpan > 180) {
          setSelectEnd(null);
          // 清除相交状态
          setIntersectedRects(new Array(dataAreas.length).fill(false));
          setIntersectedPolygons(new Array(polygons.length).fill(false));
          // 清除选区坐标显示
          onSelectionChange?.(null);
          render();
          return;
        }
        // 实时限制经度跨度不超过360度
        let finalCoord = coord;
        const rawSpan = Math.abs(coord.lng - startCoord.lng);
        if (rawSpan > 360) {
          // 超过360度，限制为360度
          if (coord.lng > startCoord.lng) {
            finalCoord = { ...coord, lng: startCoord.lng + 360 };
          } else {
            finalCoord = { ...coord, lng: startCoord.lng - 360 };
          }
          // 将限制后的终点转换为屏幕坐标
          const finalScreenCoord = latLngToScreen(finalCoord.lat, finalCoord.lng);
          const finalX = finalScreenCoord.x * scale + panX;
          const finalY = finalScreenCoord.y * scale + panY;
          setSelectEnd({ x: finalX, y: finalY });
          // 实时更新相交状态（使用限制后的坐标）
          const previewSelection = {
            minLat: Math.min(startCoord.lat, finalCoord.lat),
            maxLat: Math.max(startCoord.lat, finalCoord.lat),
            minLng: Math.min(startCoord.lng, finalCoord.lng),
            maxLng: Math.max(startCoord.lng, finalCoord.lng),
          };
          updateIntersectedState(previewSelection);
          // 实时传递选区坐标信息
          onSelectionChange?.(previewSelection);
        } else {
          setSelectEnd({ x, y });
          // 实时更新相交状态
          const previewSelection = {
            minLat: Math.min(startCoord.lat, coord.lat),
            maxLat: Math.max(startCoord.lat, coord.lat),
            minLng: Math.min(startCoord.lng, coord.lng),
            maxLng: Math.max(startCoord.lng, coord.lng),
          };
          updateIntersectedState(previewSelection);
          // 实时传递选区坐标信息
          onSelectionChange?.(previewSelection);
        }
        render();
        return;
      }

      if (isDragging && lastMousePos) {
        const deltaX = x - lastMousePos.x;
        const deltaY = y - lastMousePos.y;
        // 限制上下边界，允许左右无限循环
        const canvas = canvasRef.current;
        if (canvas) {
          const { height: mapHeight } = getMapDimensions(displayLevel);
          const mapHeightScaled = mapHeight * scale;
          const maxPanY = 0;
          const minPanY = canvas.height - mapHeightScaled;
          const clampedPanY = Math.max(minPanY, Math.min(maxPanY, panY + deltaY));
          setPanX(panX + deltaX);
          setPanY(clampedPanY);
        }
        setLastMousePos({ x, y });
        // 计算惯性速度
        const timeDelta = currentTime - lastMoveTime;
        if (timeDelta > 0) {
          const vx = (deltaX / timeDelta) * 16;
          const vy = (deltaY / timeDelta) * 16;
          setLastMoveDelta({ x: vx, y: vy });
        }
        setLastMoveTime(currentTime);
      }
      render();
    };

    const handleMouseUp = () => {
      if (isDragging) {
        // 启动惯性
        if (Math.abs(lastMoveDelta.x) > 0.5 || Math.abs(lastMoveDelta.y) > 0.5) {
          setInertia({ vx: lastMoveDelta.x, vy: lastMoveDelta.y });
          setIsInertiaActive(true);
        }
      }

      // 重置所有鼠标相关状态
      setIsMouseDown(false);
      setIsDragging(false);
      setLastMousePos(null);
      setMouseDownPos(null);
    };

    // 计算当前缩放级别
    const getZoomLevel = () => {
      if (scale < 1) return 1;
      if (scale < 2) return 2;
      if (scale < 4) return 3;
      if (scale < 8) return 4;
      if (scale < 16) return 5;
      if (scale < 32) return 6;
      if (scale < 64) return 7;
      if (scale < 128) return 8;
      if (scale < 256) return 9;
      if (scale < 512) return 10;
      // 根据maxZoom动态计算，但不超过maxZoom
      const calculatedLevel = Math.floor(Math.log2(scale)) + 1;
      return Math.min(calculatedLevel, maxZoom);
    };

    // 获取可见瓦片（基于当前视窗）
    const getVisibleTiles = (level: number) => {
      const tiles: { z: number; x: number; y: number; key: string }[] = [];

      if (level === 1) {
        // 1级只显示1_0_0
        tiles.push({ z: 1, x: 0, y: 0, key: "1_0_0" });
      } else if (level >= 2) {
        // 从2级开始使用瓦片图
        const rows = Math.pow(2, level - 1);
        const cols = Math.pow(2, level);
        
        // 计算当前视窗在地图坐标系中的范围
        const canvas = canvasRef.current;
        if (!canvas) return tiles;
        
        const canvasWidth = canvas.width;
        const canvasHeight = canvas.height;
        
        // 计算视窗在地图坐标系中的范围
        const viewportLeft = -panX / scale;
        const viewportRight = (-panX + canvasWidth) / scale;
        const viewportTop = -panY / scale;
        const viewportBottom = (-panY + canvasHeight) / scale;
        
        // 计算单个瓦片在地图坐标系中的尺寸
        const mapWidth = 2048; // 显示地图宽度
        const mapHeight = 1024; // 显示地图高度
        const totalMapWidth = cols * 1024; // 瓦片总宽度
        const totalMapHeight = rows * 1024; // 瓦片总高度
        const tileWidth = 1024 * (mapWidth / totalMapWidth);
        const tileHeight = 1024 * (mapHeight / totalMapHeight);
        
        // 计算需要加载的瓦片范围（添加缓冲区）
        const buffer = Math.max(tileWidth, tileHeight) * 0.5; // 50%的缓冲区
        const startX = Math.max(0, Math.floor((viewportLeft - buffer) / tileWidth));
        const endX = Math.min(cols - 1, Math.ceil((viewportRight + buffer) / tileWidth));
        const startY = Math.max(0, Math.floor((viewportTop - buffer) / tileHeight));
        const endY = Math.min(rows - 1, Math.ceil((viewportBottom + buffer) / tileHeight));
        
        // 只加载可见范围内的瓦片
        for (let y = startY; y <= endY; y++) {
          for (let x = startX; x <= endX; x++) {
            tiles.push({ z: level, x, y, key: `${level}_${x}_${y}` });
          }
        }
      }

      return tiles;
    };

    // 加载瓦片图
    const loadTile = (z: number, x: number, y: number) => {
      const key = `${z}_${x}_${y}`;
      let promise = tileImagePromiseCache.current.get(key);
      if (!promise) {
        promise = new Promise((resolve, reject) => {
          const img = new Image();
          img.crossOrigin = "anonymous";
          img.onload = () => {
            tileImagePromiseCache.current.delete(key);
            resolve(img);
          };
          img.onerror = () => {
            tileImagePromiseCache.current.delete(key);
            reject(new Error(`Failed to load tile ${z}_${x}_${y}`));
          };
          // 使用动态的tileUrlTemplate，替换占位符
          // 与3D视图保持一致，将坐标加1
          const tileUrl = tileUrlTemplate
            .replace("{z}", z.toString())
            .replace("{y}", (y + 1).toString())
            .replace("{x}", (x + 1).toString());
          img.src = tileUrl;
        });
        tileImagePromiseCache.current.set(key, promise);
      }
      return promise;
    };

    // 加载瓦片图
    useEffect(() => {
      const newZoomLevel = getZoomLevel();
      if (newZoomLevel !== currentZoomLevel) {
        setCurrentZoomLevel(newZoomLevel);
      }
    }, [scale, currentZoomLevel]);

    // 当tileUrlTemplate改变时，清空瓦片缓存和当前显示的瓦片
    useEffect(() => {
      tileImagePromiseCache.current.clear();
      setTileImages(new Map());
    }, [tileUrlTemplate]);

    // 加载瓦片图
    useEffect(() => {
      const loadTiles = async () => {
        tileLoadRequestId.current++;
        const currentRequestId = tileLoadRequestId.current;
        const level = currentZoomLevel;
        const visibleTiles = getVisibleTiles(level);
        const newTileImages = new Map<string, HTMLImageElement>();
        
        // 保留当前已加载的瓦片
        const currentTileImages = new Map(tileImages);
        
        setIsLoadingTiles(true);
        try {
          // 确保level1底图总是被加载
          if (!currentTileImages.has("1_0_0")) {
            try {
              const img = await loadTile(1, 0, 0);
              if (tileLoadRequestId.current !== currentRequestId) {
                return;
              }
              newTileImages.set("1_0_0", img);
            } catch (error) {
              if (tileLoadRequestId.current !== currentRequestId) {
                return;
              }
            }
          } else {
            newTileImages.set("1_0_0", currentTileImages.get("1_0_0")!);
          }
          
          if (level >= 2) {
            // 只加载当前可见但尚未加载的瓦片
            const tilesToLoad = visibleTiles.filter(tile => !currentTileImages.has(tile.key));
            
            if (tilesToLoad.length > 0) {
              const loadPromises = tilesToLoad.map(async (tile) => {
                try {
                  const img = await loadTile(tile.z, tile.x, tile.y);
                  return { key: tile.key, img };
                } catch (error) {
                  console.warn(`Failed to load tile ${tile.key}:`, error);
                  return null;
                }
              });
              
              const results = await Promise.all(loadPromises);
              if (tileLoadRequestId.current !== currentRequestId) {
                return;
              }
              
              // 将新加载的瓦片添加到缓存中
              results.forEach((result) => {
                if (result) {
                  newTileImages.set(result.key, result.img);
                }
              });
            }
            
            // 保留当前可见的瓦片
            visibleTiles.forEach(tile => {
              if (currentTileImages.has(tile.key)) {
                newTileImages.set(tile.key, currentTileImages.get(tile.key)!);
              }
            });
          }
          
          if (tileLoadRequestId.current !== currentRequestId) {
            return;
          }
          
          setTileImages(newTileImages);
          setDisplayLevel(level);
          setIsLoadingTiles(false);
        } catch (error) {
          if (tileLoadRequestId.current !== currentRequestId) {
            return;
          }
          setIsLoadingTiles(false);
        }
      };

      loadTiles();
    }, [currentZoomLevel, tileUrlTemplate, panX, panY, scale]); // 添加视窗相关依赖

    // 初始化
    useEffect(() => {
      const canvas = canvasRef.current;
      if (!canvas) return;

      // 设置画布大小
      const resizeCanvas = () => {
        const rect = canvas.parentElement?.getBoundingClientRect();
        if (rect) {
          canvas.width = rect.width;
          canvas.height = rect.height;

          // 计算地图的缩放比例，让地图高度等于容器高度
          const { height: mapHeight } = getMapDimensions(displayLevel);
          const newScale = rect.height / mapHeight;

          // 如果当前缩放比例不正确，则更新
          if (Math.abs(scale - newScale) > 0.01) {
            setScale(newScale);
          }

          render();
        }
      };

      // 手动添加wheel事件监听器，禁用passive模式
      const handleWheelEvent = (e: WheelEvent) => {
        e.preventDefault();
        e.stopPropagation();

        const rect = canvas.getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;

        const zoomFactor = e.deltaY > 0 ? 0.9 : 1.1;
        let newScale = Math.min(16, scaleRef.current * zoomFactor);

        // 确保地图最小尺寸不小于容器高度
        const minScale = rect.height / 1024; // 1024是地图高度
        newScale = Math.max(newScale, minScale);

        // 以鼠标位置为中心进行缩放
        const scaleRatio = newScale / scaleRef.current;
        const newPanX = x - (x - panXRef.current) * scaleRatio;
        const newPanY = y - (y - panYRef.current) * scaleRatio;

        // 限制上下边界
        const { height: mapHeight } = getMapDimensions(displayLevelRef.current);
        const mapHeightScaled = mapHeight * newScale; // 地图高度
        const maxPanY = 0; // 上边界
        const minPanY = rect.height - mapHeightScaled; // 下边界
        const clampedPanY = Math.max(minPanY, Math.min(maxPanY, newPanY));

        setPanX(newPanX);
        setPanY(clampedPanY);
        setScale(newScale);
      };

      resizeCanvas();
      window.addEventListener("resize", resizeCanvas);
      canvas.addEventListener("wheel", handleWheelEvent, { passive: false });

      return () => {
        window.removeEventListener("resize", resizeCanvas);
        canvas.removeEventListener("wheel", handleWheelEvent);
      };
    }, []); // 空依赖数组，只在组件挂载时执行一次

    // 惯性动画
    useEffect(() => {
      if (!isInertiaActive || (Math.abs(inertia.vx) < 0.1 && Math.abs(inertia.vy) < 0.1)) {
        setIsInertiaActive(false);
        return;
      }

      const animate = () => {
        const canvas = canvasRef.current;
        if (canvas) {
          const { height: mapHeight } = getMapDimensions(displayLevel);
          const mapHeightScaled = mapHeight * scale; // 地图高度
          const maxPanY = 0; // 上边界
          const minPanY = canvas.height - mapHeightScaled; // 下边界

          setPanX((prev) => prev + inertia.vx);
          setPanY((prev) => {
            const newPanY = prev + inertia.vy;
            return Math.max(minPanY, Math.min(maxPanY, newPanY));
          });
        }

        setInertia((prev) => ({
          vx: prev.vx * 0.95,
          vy: prev.vy * 0.95,
        }));
        render();
      };

      const interval = setInterval(animate, 16); // 60fps
      return () => clearInterval(interval);
    }, [isInertiaActive, inertia, scale]);

    // 当props变化时重新渲染
    useEffect(() => {
      render();
    }, [
      dataAreas,
      polygons,
      locationPoints,
      scale,
      panX,
      panY,
      selectionStart,
      selectionEnd,
      tileImages,
      displayLevel,
    ]);

    // 当外部选区变化时，更新相交状态
    useEffect(() => {
      if (externalSelection) {
        updateIntersectedState(externalSelection);
      } else {
        // 清除相交状态
        setIntersectedRects(new Array(dataAreas.length).fill(false));
        setIntersectedPolygons(new Array(polygons.length).fill(false));
      }
    }, [externalSelection, dataAreas.length, polygons.length]);

    // 暴露方法给父组件
    useImperativeHandle(
      ref,
      () => ({
        zoomIn: () => {
          const canvas = canvasRef.current;
          if (canvas) {
            const rect = canvas.getBoundingClientRect();
            const x = rect.width / 2;
            const y = rect.height / 2;
            let newScale = Math.min(10, scale * 1.2);

            // 确保地图最小尺寸不小于容器高度
            const minScale = rect.height / 1024; // 1024是地图高度
            newScale = Math.max(newScale, minScale);

            const scaleRatio = newScale / scale;
            const newPanX = x - (x - panX) * scaleRatio;
            const newPanY = y - (y - panY) * scaleRatio;

            // 限制上下边界
            const { height: mapHeight } = getMapDimensions(displayLevel);
            const mapHeightScaled = mapHeight * newScale;
            const maxPanY = 0;
            const minPanY = rect.height - mapHeightScaled;
            const clampedPanY = Math.max(minPanY, Math.min(maxPanY, newPanY));

            setPanX(newPanX);
            setPanY(clampedPanY);
            setScale(newScale);
          }
        },
        zoomOut: () => {
          const canvas = canvasRef.current;
          if (canvas) {
            const rect = canvas.getBoundingClientRect();
            const x = rect.width / 2;
            const y = rect.height / 2;
            let newScale = scale * 0.8;

            // 确保地图最小尺寸不小于容器高度
            const minScale = rect.height / 1024; // 1024是地图高度
            newScale = Math.max(newScale, minScale);

            const scaleRatio = newScale / scale;
            const newPanX = x - (x - panX) * scaleRatio;
            const newPanY = y - (y - panY) * scaleRatio;

            // 限制上下边界
            const { height: mapHeight } = getMapDimensions(displayLevel);
            const mapHeightScaled = mapHeight * newScale;
            const maxPanY = 0;
            const minPanY = rect.height - mapHeightScaled;
            const clampedPanY = Math.max(minPanY, Math.min(maxPanY, newPanY));

            setPanX(newPanX);
            setPanY(clampedPanY);
            setScale(newScale);
          }
        },
        resetView: () => {
          const canvas = canvasRef.current;
          if (canvas) {
            const rect = canvas.getBoundingClientRect();
            const { height: mapHeight } = getMapDimensions(displayLevel);
            // 计算缩放比例，让地图高度等于容器高度
            const newScale = rect.height / mapHeight;

            setPanX(0);
            setPanY(0);
            setScale(newScale);
          }
        },
        enterSelectionMode: () => {
          // 直接使用Meta键选区的逻辑，不需要额外的状态
        },
        exitSelectionMode: () => {
          // 直接使用Meta键选区的逻辑，不需要额外的状态
        },
        clearSelection: () => {
          // 清空选区状态
          setLastSelection(null);
          setSelectStart(null);
          setSelectEnd(null);
          setIs2DSelecting(false);
          setSelectClickCount(0);
          // 清除相交状态
          setIntersectedRects(new Array(dataAreas.length).fill(false));
          setIntersectedPolygons(new Array(polygons.length).fill(false));
          // 通知父组件选区已清空
          onSelectionChange?.(null);
          onSelectionEnd?.(null, [], []);
          // 重新渲染
          render();
        },
      }),
      [scale, panX, panY, displayLevel]
    );

    return (
      <div className="earth-2d-container">
        <canvas
          ref={canvasRef}
          className="earth-2d-canvas"
          onMouseDown={handleMouseDown}
          onMouseMove={handleMouseMove}
          onMouseUp={handleMouseUp}
          onClick={handleMouseClick}
          style={{
            cursor: is2DSelecting
              ? "crosshair"
              : simulatedMetaKey
              ? "crosshair"
              : isHoveringLocation
              ? "pointer"
              : isDragging
              ? "grabbing"
              : "grab",
          }}
        />
      </div>
    );
  }
);

export default Earth2D;
